<script lang="ts" setup>
import type { PermissionApi, RoleApi } from '#/api/types';

import { ref, watch } from 'vue';

import { useVbenDrawer } from '@vben/common-ui';

import { Card, Checkbox, Empty, message, Spin } from 'ant-design-vue';

import { getPermissionTreeApi } from '#/api/core/modules/permission';
import {
  getRolePermissionsApi,
  updateRolePermissionsApi,
} from '#/api/core/modules/role';
import { $t } from '#/locales';

// 定义事件
const emit = defineEmits<{
  (e: 'success'): void;
}>();

// 加载状态
const initialLoading = ref(true);

// 权限树
const permissionTree = ref<PermissionApi.PermissionTree[]>([]);

// 已选择的权限ID列表 - 存储字符串类型的ID
const selectedPermissionIds = ref<string[]>([]);

// 角色信息
const currentRole = ref<null | RoleApi.RoleVO>(null);

// 存储角色最初的权限集合，用于对比变更 - 存储字符串类型的ID
const originalPermissionIds = ref<string[]>([]);

// 监听角色变化重新加载权限数据
watch(
  () => currentRole.value?.id,
  (newRoleId) => {
    if (newRoleId) {
      loadRolePermissions(newRoleId);
    }
  },
  { immediate: false },
);

// 抽屉组件
const [Drawer, drawerApi] = useVbenDrawer({
  title: $t('system.role.setPermissions'),

  // 表单确认处理
  async onConfirm() {
    try {
      if (!currentRole.value?.id) {
        message.error($t('system.role.idRequired'));
        return false;
      }

      // 锁定抽屉
      drawerApi.setState({ loading: true });

      // 角色ID
      const roleId = currentRole.value.id;

      // 计算需要添加和移除的权限
      const assignPermissionIds = selectedPermissionIds.value.filter(
        (id) => !originalPermissionIds.value.includes(id),
      );
      const removePermissionIds = originalPermissionIds.value.filter(
        (id) => !selectedPermissionIds.value.includes(id),
      );

      // 使用新的接口更新角色权限
      if (assignPermissionIds.length > 0 || removePermissionIds.length > 0) {
        const updateResult = await updateRolePermissionsApi({
          roleId,
          assignPermissionIds,
          removePermissionIds,
        });

        if (!updateResult.success) {
          message.warning(
            updateResult.message || $t('system.role.permissionUpdateFailed'),
          );
          return false;
        }
      }

      message.success($t('common.operationSuccess'));
      emit('success');

      // 主动关闭抽屉
      drawerApi.close();
      return true;
    } catch {
      return false;
    } finally {
      drawerApi.setState({ loading: false });
    }
  },

  // 打开关闭处理
  onOpenChange(isOpen) {
    if (isOpen) {
      // 获取数据
      const data = drawerApi.getData<RoleApi.RoleVO>();
      if (data && data.id) {
        currentRole.value = data;
        // 加载权限数据
        loadData();
      }
    } else {
      // 关闭时重置数据
      selectedPermissionIds.value = [];
      currentRole.value = null;
      permissionTree.value = [];
    }
  },
});

// 加载所有权限数据
async function loadData() {
  initialLoading.value = true;
  try {
    // 获取权限类别树
    const result = await getPermissionTreeApi();

    // 处理返回的权限树数据
    if (result?.data) {
      permissionTree.value = Array.isArray(result.data)
        ? result.data
        : [result.data];
    } else if (Array.isArray(result)) {
      permissionTree.value = result;
    } else {
      permissionTree.value = [];
    }

    // 如果有角色ID，加载角色权限
    if (currentRole.value?.id) {
      await loadRolePermissions(currentRole.value.id);
    }
  } catch {
    message.error($t('common.loadFailed'));
  } finally {
    initialLoading.value = false;
  }
}

// 加载角色已分配的权限
async function loadRolePermissions(roleId: number) {
  try {
    // 获取角色已分配的权限
    const rolePermissionResult = await getRolePermissionsApi(roleId);

    // 解析权限ID列表
    let permissionIds: string[] = [];

    // 数据可能在result.data中，或者直接在result中
    const permissionData = rolePermissionResult?.data || rolePermissionResult;

    if (Array.isArray(permissionData)) {
      // 处理返回的权限数据
      permissionIds = permissionData
        .map((item) => {
          // 如果是对象数组，提取id属性
          if (typeof item === 'object' && item !== null && 'id' in item) {
            return String(item.id); // 确保ID为字符串类型
          }
          // 如果直接是数字或字符串ID
          return String(item); // 确保ID为字符串类型
        })
        .filter(Boolean); // 过滤掉空值
    }

    // 更新选中状态
    selectedPermissionIds.value = [...permissionIds];
    originalPermissionIds.value = [...permissionIds]; // 存储初始状态
  } catch {
    message.error($t('common.loadFailed'));
  }
}

// 处理权限选择
function handlePermissionChange(permissionId: string, checked: boolean) {
  if (checked) {
    // 添加到选中列表
    if (!selectedPermissionIds.value.includes(permissionId)) {
      selectedPermissionIds.value.push(permissionId);
    }
  } else {
    // 从选中列表移除
    const index = selectedPermissionIds.value.indexOf(permissionId);
    if (index !== -1) {
      selectedPermissionIds.value.splice(index, 1);
    }
  }
}

// 切换分类下所有权限
function toggleCategoryPermissions(
  category: PermissionApi.PermissionTree,
  checked: boolean,
) {
  if (!category.children || !Array.isArray(category.children)) return;

  // 确保ID为字符串类型
  const permissionIds = category.children.map((p) => String(p.id));

  if (checked) {
    // 添加该分类下所有权限
    permissionIds.forEach((id) => {
      if (!selectedPermissionIds.value.includes(id)) {
        selectedPermissionIds.value.push(id);
      }
    });
  } else {
    // 移除该分类下所有权限
    selectedPermissionIds.value = selectedPermissionIds.value.filter(
      (id) => !permissionIds.includes(id),
    );
  }
}

// 计算分类的全选状态
function getCategoryCheckStatus(category: PermissionApi.PermissionTree) {
  if (
    !category.children ||
    !Array.isArray(category.children) ||
    category.children.length === 0
  ) {
    return false;
  }

  const permissionIds = category.children.map((p) => String(p.id));

  // 确保字符串类型比较一致
  const selectedPermissionIdsInCategory = permissionIds.filter((id) =>
    selectedPermissionIds.value.includes(id),
  ).length;

  if (selectedPermissionIdsInCategory === 0) return false;
  if (selectedPermissionIdsInCategory === permissionIds.length) return true;
  return 'indeterminate';
}

// 暴露抽屉API给父组件
defineExpose({
  drawerApi,
});
</script>

<template>
  <Drawer class="w-[700px]">
    <div>
      <div class="mb-2">
        <div class="flex items-center">
          <span class="text-base font-medium">{{ currentRole?.name }}</span>
          <span class="ml-1 text-xs text-gray-500">
            ({{ currentRole?.code }})
          </span>
        </div>
        <p class="text-xs text-gray-500">{{ currentRole?.description }}</p>
      </div>

      <Spin :spinning="initialLoading">
        <div class="permission-container">
          <div class="mb-2 text-xs text-gray-500">
            {{
              $t('system.role.permissionTip') || '请选择要分配给该角色的权限'
            }}
          </div>

          <Empty
            v-if="permissionTree.length === 0"
            :description="$t('common.noData')"
            :image-style="{ height: '40px' }"
          />

          <div v-else class="permission-category-list">
            <Card
              v-for="category in permissionTree"
              :key="category.id"
              class="mb-2"
              :bordered="true"
              :head-style="{ background: '#f6f8fa', padding: '6px 12px' }"
              :body-style="{ padding: '8px 12px' }"
            >
              <!-- 分类标题与全选控制 -->
              <template #title>
                <div class="flex items-center">
                  <Checkbox
                    :checked="getCategoryCheckStatus(category) === true"
                    :indeterminate="
                      getCategoryCheckStatus(category) === 'indeterminate'
                    "
                    @change="
                      (e) =>
                        toggleCategoryPermissions(category, e.target.checked)
                    "
                  >
                    <span class="text-sm font-medium">{{ category.name }}</span>
                  </Checkbox>
                </div>
              </template>

              <!-- 分类下的权限列表 -->
              <div
                v-if="category.children && category.children.length > 0"
                class="permission-list"
              >
                <div class="grid grid-cols-4 gap-2">
                  <div
                    v-for="permission in category.children"
                    :key="permission.id"
                    class="permission-item"
                  >
                    <Checkbox
                      :checked="
                        selectedPermissionIds.includes(String(permission.id))
                      "
                      :disabled="permission.status === 0"
                      @change="
                        (e) =>
                          handlePermissionChange(
                            String(permission.id),
                            e.target.checked,
                          )
                      "
                    >
                      <div class="permission-info">
                        <div class="permission-name text-xs">
                          {{ permission.name }}
                        </div>
                        <div class="permission-code text-xs text-gray-400">
                          {{ permission.code }}
                        </div>
                      </div>
                    </Checkbox>
                  </div>
                </div>
              </div>
              <Empty
                v-else
                :description="$t('system.permission.noCategoryPermission')"
                :image-style="{ height: '40px' }"
              />
            </Card>
          </div>
        </div>
      </Spin>
    </div>
  </Drawer>
</template>

<style scoped>
.permission-container {
  overflow-y: auto;
}

.permission-category-list {
  margin-bottom: 0.5rem;
}

.permission-item {
  padding: 0;
  margin-bottom: 0.25rem;
  border-radius: 3px;
  transition: all 0.2s;
}

.permission-item:hover {
  background-color: #f5f7fa;
}

.permission-info {
  padding: 0;
  line-height: 1.2;
}

:deep(.ant-card-head) {
  min-height: auto;
}

:deep(.ant-card-body) {
  padding-top: 6px;
  padding-bottom: 6px;
}

:deep(.ant-checkbox-wrapper) {
  font-size: 12px;
}

:deep(.ant-empty) {
  margin: 8px 0;
}

:deep(.ant-empty-image) {
  height: 40px;
}

:deep(.ant-empty-description) {
  font-size: 12px;
}
</style>
